#ifndef CMD_APP_H
#define CMD_APP_H

#include <stdbool.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>

#ifdef __cplusplus
extern "C" {
#endif

#define NTOP(in_addr, buf) inet_ntop(AF_INET, (in_addr), (buf), INET_ADDRSTRLEN)
#define PTON(buf,addr) inet_pton(AF_INET, (buf), (addr))
#define NTOP6(in_addr, buf) inet_ntop(AF_INET6, (in_addr), (buf), INET6_ADDRSTRLEN)
#define PTON6(buf,addr) inet_pton(AF_INET6, (buf), (addr))

static inline bool str2u64(const char *str, uint64_t *u)
{
  char  *endptr = NULL;
  unsigned long long int tmp = strtoull(str, &endptr, 0);
  if (endptr == NULL || *endptr != 0) {
    return false;
  }
  
  *u = (uint64_t)tmp;
  return true;
}

static inline bool str2u32(const char *str,uint32_t *u)
{
  char  *endptr = NULL;
  unsigned long int tmp=strtoul(str, &endptr, 0);
  if (endptr == NULL || *endptr != 0 || tmp > 0xffffffff) {
    return false;
  }
  *u = (uint32_t)tmp;
  return true;
}

static inline bool str2u16(const char *str,uint16_t *u)
{
  uint32_t tmp = 0;
  if(!str2u32(str, &tmp) || tmp > 0xffff) {
    return false;
  }
  *u = (uint16_t)tmp;
  return true;
}


static inline bool str2u8(const char *str,uint8_t *u)
{
  uint16_t tmp = 0;
  if(!str2u16(str, &tmp) || tmp > 0xff){
    return false;
  }
  *u = (uint8_t)tmp;
  return true;
}

static inline bool hex2u64(const char *str, uint64_t *u)
{
  char  *endptr;
  unsigned long long int tmp;
  
  tmp = strtoull(str, &endptr, 16);
  if (endptr == NULL || *endptr != 0) {
    return false;
  }
  
  *u = (uint64_t)tmp;
  return true;
}

static inline bool hex2u32(const char *str,uint32_t *u)
{
  char  *endptr;
  unsigned long int tmp;
  tmp=strtoul(str, &endptr, 16);
  if (endptr == NULL || *endptr != 0 || tmp > 0xffffffff) {
    return false;
  }
  *u = (uint32_t)tmp;
  return true;
}

static inline bool ip2u32(const char *buf, uint32_t *ip)
{
   uint32_t net_ip=0xffffffff;
   if (PTON(buf, &net_ip) > 0 && ip != NULL) {
      *ip = ntohl(net_ip);
      return true;
   } else {
      return false;
   }
}

static inline const char *ip2str(uint32_t ip, char *buf)
{
   uint32_t net_ip = htonl(ip);
   NTOP(&net_ip, buf);
   return buf;
}

static inline bool str2ip6(const char *buf, void *ip)
{
   uint16_t *ipv6 = (uint16_t *)ip;      

   if (!buf || !ipv6) {
      return false;
   }
   
   if (PTON6(buf, ipv6) > 0) {
      int n;
      for (n = 0; n < 8; n++) {
          ipv6[n] = ntohs(ipv6[n]);
      }
      return true;
   }

   return false;
}

static inline bool ip2addr(const char *buf, struct sockaddr *addr)
{
   char data[16];
   if (PTON(buf, data) > 0) {
      struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
      v4->sin_family = AF_INET;
      memcpy(&v4->sin_addr, data, sizeof(v4->sin_addr));
   } else if (PTON6(buf, data) > 0) {
      struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
      v6->sin6_family = AF_INET6;
      memcpy(&v6->sin6_addr, data, sizeof(v6->sin6_addr));
   } else {
		struct sockaddr_un *un = (struct sockaddr_un *)addr;
		un->sun_family = AF_UNIX;
		strncpy(un->sun_path, buf, 100);
		un->sun_path[100] = 0;
	} 
      return true;
}

static inline uint16_t port4addr(struct sockaddr *addr)
{
   if (addr->sa_family == AF_INET) {
      struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
      return ntohs(v4->sin_port);
   } else if (addr->sa_family == AF_INET6) {
      struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
      return ntohs(v6->sin6_port);
   } else 
      return 0;
}

static inline char *ipstr4addr(struct sockaddr *addr, char *buf, int len)
{
   if (addr->sa_family == AF_INET) {
      struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
      inet_ntop(AF_INET, &v4->sin_addr, buf, len);
   } else if (addr->sa_family == AF_INET6) {
      struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
      inet_ntop(AF_INET, &v6->sin6_addr, buf, len);
   } else 
      buf[0] = 0;
   return buf;      
}


extern int g_debug;

static inline bool cmd_in_debug(void)
{
   return g_debug != 0;
}

#define kw_argz_pop pop_argz

static inline uint32_t kw_get_flags(struct kw *kw)
{
   uint32_t flags = 0;
   if (kw == NULL)
      flags |= KW_FLAG_NULL;
   else
      flags |= kw->flag;
   return flags;
}

static inline bool kw_has_flags(struct kw *kw, uint32_t flags)
{
   return (kw_get_flags(kw) & flags) == flags;
}

#ifdef __cplusplus
}
#endif

#endif
